/*
 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
 *
 *  This file is licensed to You under the Eclipse Public License (EPL);
 *  You may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *      http://www.opensource.org/licenses/eclipse-1.0.php
 *
 *  See the COPYRIGHT.txt file distributed with this work for information
 *  regarding copyright ownership.
 */
package org.jikesrvm.adaptive;

import org.jikesrvm.adaptive.controller.Controller;
import org.jikesrvm.adaptive.controller.ControllerInputEvent;
import org.jikesrvm.adaptive.controller.ControllerMemory;
import org.jikesrvm.adaptive.controller.ControllerPlan;
import org.jikesrvm.adaptive.util.AOSLogging;
import org.jikesrvm.classloader.NormalMethod;
import org.jikesrvm.compilers.common.CompiledMethod;
import org.jikesrvm.compilers.common.CompiledMethods;
import org.jikesrvm.compilers.common.RuntimeCompiler;
import org.jikesrvm.compilers.opt.OptOptions;
import org.jikesrvm.compilers.opt.driver.CompilationPlan;
import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement;
import org.jikesrvm.scheduler.RVMThread;
import org.vmmagic.unboxed.Offset;

/**
 * Event generated by a thread aware of on-stack-replacement request.
 * The event is feed to the controller with suspended thread, and hot
 * method id. Since it does not need to go through analytic model, it does
 * not extend the HotMethodEvent.
 */

public final class OnStackReplacementEvent implements ControllerInputEvent {

  /** the suspended thread. */
  public RVMThread suspendedThread;

  /** remember where it comes from */
  public int whereFrom;

  /** the compiled method id */
  public int CMID;

  /** the threadSwithFrom fp offset */
  public Offset tsFromFPoff;

  /** the osr method's fp offset */
  public Offset ypTakenFPoff;

  /**
   * This function will generate a controller plan and
   * inserted in the recompilation queue.
   */
  public void process() {

    CompiledMethod compiledMethod = CompiledMethods.getCompiledMethod(CMID);

    NormalMethod todoMethod = (NormalMethod) compiledMethod.getMethod();

    double priority;
    OptOptions options;
    OptimizationPlanElement[] optimizationPlan;

    ControllerPlan oldPlan = ControllerMemory.findLatestPlan(todoMethod);

    if (oldPlan != null) {
      CompilationPlan oldCompPlan = oldPlan.getCompPlan();
      priority = oldPlan.getPriority();
      options = oldCompPlan.options;
      optimizationPlan = oldCompPlan.optimizationPlan;
    } else {
      priority = 5.0;
      options = (OptOptions) RuntimeCompiler.options;
      optimizationPlan = (OptimizationPlanElement[]) RuntimeCompiler.optimizationPlan;
    }

    CompilationPlan compPlan = new CompilationPlan(todoMethod, optimizationPlan, null, options);

    OnStackReplacementPlan plan =
        new OnStackReplacementPlan(this.suspendedThread,
                                       compPlan,
                                       this.CMID,
                                       this.whereFrom,
                                       this.tsFromFPoff,
                                       this.ypTakenFPoff,
                                       priority);

    Controller.compilationQueue.insert(priority, plan);

    AOSLogging.logger.logOsrEvent("OSR inserts compilation plan successfully!");

    // do not hold the reference anymore.
    suspendedThread = null;
    CMID = 0;
  }
}
